#[macro_export]
macro_rules! create_table {
    ($path:ident,$txn:ident,$builder:ident,$schema:ident) => {
        if !$path::Entity::find().one(&$txn).await.is_ok() {
            let stmt = $builder.build(&$schema.create_table_from_entity($path::Entity));
            $txn.execute(stmt).await?;
            for index_stmt in $schema.create_index_from_entity($path::Entity){
                $txn.execute($builder.build(&index_stmt)).await?;
            }
        }
    };
}

#[macro_export]
macro_rules! __gen_filter {
    ($sql:expr, $model:ident, $col:ident.$method:ident($value:ident:$($opt:tt)+), $($col2:ident.$method2:ident($value2:ident:$($opt2:tt)+)),*) => {
        $crate::__gen_filter!($crate::__gen_filter!($sql,$model,$col.$method($value:$($opt)+)), $model, $($col2.$method2($value2:$($opt2)+)),*)
    };

    ($sql:expr, $model:ident, $col:ident.$method:ident($value:ident:Option<$type_:ty>)) => {
        $sql.apply_if($value, |sql, value| {sql.filter($model::Column::$col.$method(value))})
    };

    ($sql:expr, $model:ident, $col:ident.$method:ident($value:ident:$type_:ty)) => {
        $sql.filter($model::Column::$col.$method($value))
    };

    ($sql:expr, $model:ident,) => {
        $sql
    };
}

/// 生成Option类型
#[macro_export]
macro_rules! __opt_type{
    ($p_type:ident)=>{
        $p_type
    };
    ($p_type:ident,$opt:ident)=>{
        Option<$p_type>
    }
}

/// 是否为Option类型
#[macro_export]
macro_rules! __is_opt_type {
    (Option<$p_type:ty>) => {
        true
    };
    ($p_type:ty) => {
        false
    };
}

/// 生成获取一个model的宏
/// ``` no-run
/// model_fetch!(
///     #model = model_name
///     #filter=[state.eq(false)]
///     pub fn fetch_one(Id.eq(id:i32))
/// )
/// ```
#[macro_export]
macro_rules! model_fetch {
    (
        #model = $model:ident
        $(#filter = [$($f_col:ident.$f_m:ident($f_v:expr)),*])?
        $(#order = [$($order:ident:$order_dir:ident),*])?
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident.$p_m:ident($param:ident:$($p_type:tt)+)),*)
    ) => {
        $(#[$m])*
        #[inline]
        $vis async fn $fn_name<T>(conn: &impl ConnectionTrait, $($param:$($p_type)+),*) -> std::result::Result<Option<T>, sea_orm::DbErr>
        where
            T: PartialModelTrait + Send + Sync,
        {
            $crate::__gen_filter!($model::Entity::find(), $model, $($col.$p_m($param:$($p_type)+)),*)
                $($(.filter($model::Column::$f_col.$f_m($f_v)))*)?
                $($(.order_by($model::Column::$order, sea_orm::Order::$order_dir))*)?
                .into_partial_model()
                .one(conn)
                .await
        }
    };
    (
        #model = $model:ident
        $(#filter = [$($f_col:ident.$f_m:ident($f_v:expr)),*])?
        $(#order = [$($order:ident:$order_dir:ident),*])?
        #exec=all
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident.$p_m:ident($param:ident:$($p_type:tt)+)),*)
    ) => {
        $(#[$m])*
        #[inline]
        $vis async fn $fn_name<T>(conn: &DbConn, $($param:$($p_type)+),*) -> std::result::Result<Vec<T>, sea_orm::DbErr>
        where
            T: PartialModelTrait + Send + Sync,
        {
            $crate::__gen_filter!($model::Entity::find(), $model, $($col.$p_m($param:$($p_type)+)),*)
                $($(.filter($model::Column::$f_col.$f_m($f_v)))*)?
                $($(.order_by($model::Column::$order, sea_orm::Order::$order_dir))*)?
                .into_partial_model()
                .all(conn)
                .await
        }
    };
}

#[macro_export]
macro_rules! model_create {
    (
        #model = $model:ident
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident.$p_m:ident($param:ident:$($p_type:tt)+)),*){
            $($token:tt)*
        }
    ) => {
        $(#[$m])*
        #[inline]
        $vis async fn $fn_name<AM:Into<$model::ActiveModel>>(
            conn: &DbConn,
            $($param:$($p_type)+,)*
            mut data: AM
        ) -> std::result::Result<$model::Model, sea_orm::DbErr>
        {
            use sea_orm::ActiveValue::Set;
            let mut data: $model::ActiveModel = data.into();
            // // 定义一个函数来包含用户的代码
            $($token)*
            data.insert(conn).await
        }
    };
}

/// 创建列出model的宏
///
/// 创建一个函数，前三个参数是conn, page, page_size
///
/// 函数返回值是（Vec<T:PartialModelTrait>, num）
/// ```no-run
/// model_list!(
///     # model=model_name
///     # filter=[state.eq(false)]
///     # order=[cdate:Desc]
///     pub fn list_model(Id.eq(id:i32))
/// );
/// ```
#[macro_export]
macro_rules! model_list {
    (
        #model = $model:ident
        $(#filter = [$($f_col:ident.$f_m:ident($f_v:expr)),*])?
        $(#order = [$($order:ident:$order_dir:ident),*])?
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident.$p_m:ident($param:ident:$($p_type:tt)+)),* $(,)?)
    ) => {
        $(#[$m])*
        $vis async fn $fn_name<T>(
            conn: &DbConn,
            page: u64,
            page_size: u64,
            $($param:$($p_type)+),*
        ) -> std::result::Result<(Vec<T>, u64), sea_orm::DbErr>
        where
            T: PartialModelTrait + Send + Sync,
        {
            use sea_orm::{QueryTrait, QueryFilter, QueryOrder, QuerySelect};
            let sql = $crate::__gen_filter!($model::Entity::find(), $model , $($col.$p_m($param:$($p_type)+)),*)
                $($(.filter($model::Column::$f_col.$f_m($f_v)))*)?
                $($(.order_by($model::Column::$order, sea_orm::Order::$order_dir))*)?
                .into_partial_model()
                .paginate(conn, page_size);
            let total = sql.num_items().await?;
            let datas = sql.fetch_page(page).await?;
            Ok((datas, total))
        }
    };
}

#[macro_export]
macro_rules! model_delete {
    (
        #model = $model:ident
        $(#filter = [$($f_col:ident.$f_m:ident($f_v:expr)),*])?
        $(#[$m:meta])*
        $vis:vis fn $fn_name:ident($($col:ident.$p_m:ident($param:ident:$($p_type:tt)+)),*)
    ) => {
        $(#[$m])*
        #[inline]
        $vis async fn $fn_name(conn: &DbConn, $($param:$($p_type)+),*) -> std::result::Result<(), sea_orm::DbErr>
        {
            $crate::__gen_filter!($model::Entity::delete_many(), $model, $($col.$p_m($param:$($p_type)+)),*)
                $($(.filter($model::Column::$f_col.$f_m($f_v)))*)?
                .exec(conn)
                .await
                .map(|_|())
        }
    }
}

#[macro_export]
macro_rules! model_struct {
    (
        #model=$model:ident
        $(#[$m:meta])*
        $vis:vis struct $name:ident{
            $(
                $(#[$f_meta:meta])*
                $f_vis:vis $field:ident: $p_type:ty $(,opt)?
            ),*
            $(,)?
        }
    ) => {
        $(#[$m])*
        $vis struct $name{
            $(
                $(#[$f_meta])*
                $f_vis $field: $p_type,
            )*
        }

        impl Into<$model::ActiveModel> for $name {
            fn into(self) -> $model::ActiveModel {
                $model::ActiveModel{
                    $($field:sea_orm::Set(self.$field),)*
                    ..Default::default()
                }
            }
        }
    };
}
